
#include <BFile>
#include <BDate>
#include <BTime>
#include <BFont>
#include <BWidget>
#include <BSpring>
#include <BReadWrite>
#include <BSystem>
#include <BDisk>
#include <BStyle>
#include <BListItem>
#include <BCursor>
#include "member_BFileDialog.h"

using namespace BWE;

inline bool CheckWord(const BString& text)
{
	if (text.empty())
		return false;
	const char* cstr = text.cstr();
	for (int i = 0; i < text.size(); i++)
	{
		char c = cstr[i];
		if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
			continue;
		if (c == '_')
			continue;
		return false;
	}
	return true;
}

member_BFileDialog::member_BFileDialog(BFileDialog* fileDialog)
{
	boss = fileDialog;
	dirtyStyle = false;
	attribFilter = Attrib_All;
	selectMultiple = true;
	style = 0;
	pathIndex = 0;

	topLayout = new BHBoxLayout("top");
	topLayout->setSpacing(3);
	{
		prevButton = new BButton(Graph_Arrow_Left_Fill);
		prevButton->setName("prev");
		prevButton->setForm(Form_IconAlone);

		nextButton = new BButton(Graph_Arrow_Right_Fill);
		nextButton->setName("next");
		nextButton->setForm(Form_IconAlone);

		aboveButton = new BButton(Graph_Arrow_Up_Fill);
		aboveButton->setName("above");
		aboveButton->setForm(Form_IconAlone);

		pathComboBox = new BComboBox();
		pathComboBox->setName("path");

		viewComboBox = new BComboBox();
		viewComboBox->setName("view");
		viewComboBox->setArrowShown(false);
		viewComboBox->addItem("details", 0)->setName("details");
		viewComboBox->addItem("small icon", 36)->setName("small");
		viewComboBox->addItem("middle icon", 64)->setName("middle");
		viewComboBox->addItem("big icon", 128)->setName("big");
		viewComboBox->setValue(0);

		topLayout->addWidget(prevButton);
		topLayout->addWidget(nextButton);
		topLayout->addWidget(aboveButton);
		topLayout->addWidget(pathComboBox, 100);
		topLayout->addWidget(viewComboBox, 0);
	}

	BVBoxLayout* indexesLayout = new BVBoxLayout();
	{
		listWidget = new BListWidget();
		listWidget->setName("list");
		listWidget->setSelectMode(Select_Single);
		listWidget->setScrollPolicy(ScrollPolicy_Never);
		listWidget->setAreaPolicy(Policy_Preferred);

		treeWidget = new BTreeWidget();
		treeWidget->setName("tree");
		treeWidget->setSelectMode(Select_Single);

		indexesLayout->addWidget(listWidget, 0);
		indexesLayout->addWidget(treeWidget);
	}

	tableWidget = new BTableWidget();
	tableWidget->setName("table");
	tableWidget->setSelectMode(Select_Multiple | Select_Rows);
	tableWidget->setColumnSpacing(10);

	splitLayout = new BHBoxLayout();
	splitLayout->setSplitable(true);
	splitLayout->setSpacing(6);
	splitLayout->addLayout(indexesLayout, 1);
	splitLayout->addWidget(tableWidget, 3);

	BVBoxLayout* layout = new BVBoxLayout(boss);
	layout->setSpacing(3);
	layout->addLayout(topLayout);
	layout->addLayout(splitLayout, 1000);

	BVBoxLayout* bottomLayout = new BVBoxLayout(boss, Part_Bottom);
	{
		BHBoxLayout* nameLayout = new BHBoxLayout();
		nameLayout->setMargin(2);
		nameLayout->setSpacing(3);
		{
			BLabel* nameLabel = new BLabel("name");
			nameLabel->setAlign(Align_Center);

			nameEdit = new BLineEdit();

			filterComboBox = new BComboBox();

			nameLayout->addSpring(3);
			nameLayout->addWidget(nameLabel, 1);
			nameLayout->addWidget(nameEdit, 10);
			nameLayout->addWidget(filterComboBox, 1);
		}
		BHBoxLayout* buttonLayout = new BHBoxLayout();
		buttonLayout->setMargin(2);
		buttonLayout->setSpacing(3);
		{
			okButton = new BButton("Ok");
			okButton->setName("ok");
			okButton->setMinSize(BSize(100, 0));
			cancleButton = new BButton("Cancel");
			cancleButton->setName("cancel");
			cancleButton->setMinSize(BSize(100, 0));

			buttonLayout->addSpring();
			buttonLayout->addWidget(okButton);
			buttonLayout->addWidget(cancleButton);
		}
		bottomLayout->addLayout(nameLayout);
		bottomLayout->addLayout(buttonLayout);
	}

	connect(prevButton, Signal_Clicked, &member_BFileDialog::slotBackButtonClicked);
	connect(nextButton, Signal_Clicked, &member_BFileDialog::slotFrontButtonClicked);
	connect(aboveButton, Signal_Clicked, &member_BFileDialog::slotAboveButtonClicked);
	connect(pathComboBox, Signal_TextChanged, &member_BFileDialog::slotPathTextChanged);
	connect(viewComboBox, Signal_TextChanged, &member_BFileDialog::slotViewTextChanged);

	connect(listWidget, Signal_ItemClicked, &member_BFileDialog::slotListItemClicked);

	connect(treeWidget, Signal_ItemClicked, &member_BFileDialog::slotTreeItemClicked);
	connect(treeWidget, Signal_ItemDoubleClicked, &member_BFileDialog::slotTreeItemDoubleClicked);
	connect(treeWidget, Signal_AreaChanged, &member_BFileDialog::slotScrollAreaChanged);

	connect(tableWidget, Signal_Frame, &member_BFileDialog::slotTableWidgetFramed);
	connect(tableWidget, Signal_Resize, &member_BFileDialog::slotTableWidgetResized);
	connect(tableWidget, Signal_AreaChanged, &member_BFileDialog::slotScrollAreaChanged);
	connect(tableWidget, Signal_ItemClicked, &member_BFileDialog::slotTableItemClicked);
	connect(tableWidget, Signal_ItemHovered, &member_BFileDialog::slotTableItemHovered);
	connect(tableWidget, Signal_ItemDoubleClicked, &member_BFileDialog::slotTableItemDoubleClicked);
	connect(tableWidget, Signal_SelectionChanged, &member_BFileDialog::slotTableWidgetSelectionChanged);

	connect(nameEdit, Signal_TextEdited, &member_BFileDialog::slotNameEdited);
	connect(filterComboBox, Signal_CurrentChanged, &member_BFileDialog::slotNameFilterChanged);
	connect(okButton, Signal_Clicked, &member_BFileDialog::slotOkClicked);
	connect(cancleButton, Signal_Clicked, &member_BFileDialog::slotCancleClicked);

	resetDisks();
}
member_BFileDialog::~member_BFileDialog()
{

}

const char* member_BFileDialog::typeName(BEntry* entry)
{
	Attrib attrib = entry->attrib();
	if (attrib &  Attrib_Folder)
		return "folder";
	if (attrib &  Attrib_Link)
		return "link";
	if (attrib &  Attrib_Pipe)
		return "pipe";
	if (attrib &  Attrib_Block)
		return "block";
	if (attrib &  Attrib_Char)
		return "char";
	if (attrib &  Attrib_Socket)
		return "socket";
	if (attrib & Attrib_File)
	{
		const BString& fileName = entry->name();
		return fileName.ext();
	}
	return "*";
}
BIcon* member_BFileDialog::iconOf(BObject* object)
{
	BIcon* icon = 0;
	if (style)
	{
		if (BDisk* disk = dynamic_cast<BDisk*>(object))
		{
			icon = BSystem::EntryIcon(disk->name());
			if (icon == 0)
			{
				switch (disk->type())
				{
				case BDisk::Root:
					icon = style->icon("disk-root");
					break;
				case BDisk::Removable:
					icon = style->icon("disk-usb");
					break;
				case BDisk::Remote:
					icon = style->icon("disk-cloud");
					break;
				case BDisk::CDRom:
					icon = style->icon("disk-cd");
					break;
				case BDisk::Symbol:
					icon = style->icon("disk-symbol");
					break;
				default:
					icon = style->icon("disk");
					break;
				}
			}
		}
		if (!icon)
		{
			if (BEntry* entry = dynamic_cast<BEntry*>(object))
			{
				if (entry->attrib() & Attrib_Folder)
					icon = style->icon("folder");
				if (entry->attrib() & Attrib_Link)
					icon = style->icon("link");
				if (!icon)
					icon = BSystem::EntryIcon(entry->path());
			}
		}
		if (!icon)
		{
			BString ext(object->name().ext());
			ext.lower();
			icon = style->icon(ext);
		}
		if (!icon)
		{
			icon = style->icon("unknown");
		}
		if (!icon)
		{
			if (unknownIcon.empty())
			{
				const BFont* font = style->font();
				BImage* image = (BImage*)font->image('?');
				unknownIcon = new BIcon(image);
			}
			icon = unknownIcon;
		}
	}
	return icon;
}
BListItem* member_BFileDialog::symbolItem(const BString& path)
{
	for (int i = 0; i < listWidget->itemCount(); i++)
	{
		BListItem* item = listWidget->item(i);
		BDisk* disk = item->asset();
		if(disk->asset() == path)
		{
			return item;
		}
	}
	return 0;
}
bool member_BFileDialog::checkImage(EntryInfo& info) const
{
	if (info.typeStr == "jpg" || info.typeStr == "jpeg")
		return true;
	if (info.typeStr == "png")
		return true;
	if (info.typeStr == "tif" || info.typeStr == "tiff")
		return true;
	if (info.typeStr == "bmp")
		return true;
	int pos = imageExts.find(info.typeStr);
	return pos < imageExts.size();
}

void member_BFileDialog::resetDisks()
{
	for (int i = 0; i < BSystem::GetDiskNumber(); i++)
	{
		BDisk* disk = BSystem::GetDisk(i);
		BString name = disk->name();
		name.remove("\\");
		if (disk->type() == BDisk::Symbol)
		{
			BListItem* symbolItem = listWidget->addItem(name);
			symbolItem->setIcon(iconOf(disk));
			symbolItem->setAsset(disk);
		}
		else
		{
			BTreeItem* topItem = treeWidget->addTopItem(name);
			topItem->setIcon(iconOf(disk));
			topItem->setAsset(disk);
		}
	}
}
void member_BFileDialog::freshListItems()
{
	for (int i = 0; i < listWidget->itemCount(); i++)
	{
		BListItem* item = listWidget->item(i);
		BObject* object = item->asset();
		item->setIcon(iconOf(object));
		if (style)
		{
			BString typeName;
			style->translate(object->name(), typeName);
			item->setText(typeName);
		}
		else
		{
			item->setText(object->name());
		}
	}
}
void member_BFileDialog::freshTreeItem(BTreeItem* item)
{
	if (BObject* object = item->asset())
	{
		BIcon* icon = iconOf(object);
		item->setIcon(icon);
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			freshTreeItem(child);
		}
	}
}
void member_BFileDialog::freshTableItems()
{
	for (int r = 0; r < tableWidget->rowCount(); r++)
	{
		for (int c = 0; c < tableWidget->columnCount(); c++)
		{
			BTableItem* item = tableWidget->item(r, c);
			if (!item)
				continue;
			BEntry* entry = item->asset();
			if (entry && !item->image())
			{
				BIcon* icon = iconOf(entry);
				item->setIcon(icon);
			}
		}
	}
	if (style)
	{
		for (int i = 0; i < entryInfos.size(); i++)
		{
			EntryInfo& info = entryInfos[i];
			style->translate(info.typeStr, info.t_typeStr);
		}
	}
	else
	{
		for (int i = 0; i < entryInfos.size(); i++)
		{
			EntryInfo& info = entryInfos[i];
			info.t_typeStr.clear();
		}
	}
}
void member_BFileDialog::freshBackFrontButton()
{
	if (pathIndex < 0)
		pathIndex = 0;
	if (pathIndex > pathRecords.size())
		pathIndex = pathRecords.size();
	const BString& path = pathComboBox->text();
	prevButton->setEnabled(pathIndex > 0);
	nextButton->setEnabled(pathIndex < pathRecords.size() - 1);
}
void member_BFileDialog::arrangeTableItems()
{
	const BString& viewStr = viewComboBox->text();
	if (viewStr == "details")
	{
		tableItems.clear();
		tableWidget->setSelectMode(Select_Multiple | Select_Rows);
		tableWidget->setRowSpacing(2);
		tableWidget->setColumnHeaderShown(true);
		tableWidget->setRowHeaderShown(true);
		tableWidget->setHorizontalScrollPolicy(ScrollPolicy_Floating);
		tableWidget->setColumnCount(4);
		tableWidget->setColumnLabel(0, "Name");
		tableWidget->setColumnLabel(1, "Type");
		tableWidget->setColumnLabel(2, "Date");
		tableWidget->setColumnLabel(3, "Size");
		tableWidget->setColumnSortable(0, true);
		tableWidget->setColumnSortable(1, true);
		tableWidget->setColumnSortable(2, true);
		tableWidget->setColumnSortable(3, true);
		tableWidget->setColumnWidth(0, 200);
		tableWidget->setRowCount(entryInfos.size());
		for (int i = 0; i < entryInfos.size(); i++)
		{
			tableWidget->setRowLabel(i, i);
			EntryInfo& info = entryInfos[i];
			BTableItem* item = tableWidget->item(i, 0);
			if(!item)
			{
				item = new BTableItem();
				tableWidget->setItem(i, 0, item);
			}
			item->setIcon(0);
			item->setImage(0);
			item->setText(info.entry->name());
			item->setForm(Form_IconText);
			item->setAlign(Align_None);
			item->setAsset(info.entry);
			item->setIconSize(0);

			BTableItem* typeItem = tableWidget->item(i, 1);
			if(!typeItem)
			{
				typeItem = new BTableItem();
				tableWidget->setItem(i, 1, typeItem);
			}
			typeItem->setIcon(0);
			typeItem->setImage(0);
			if(info.t_typeStr.size())
				typeItem->setText(info.t_typeStr);
			else
				typeItem->setText(info.typeStr);
			typeItem->setForm(Form_IconText);
			typeItem->setAlign(Align_None);
			typeItem->setAsset(0);
			typeItem->setIconSize(0);

			BTableItem* timeItem = tableWidget->item(i, 2);
			if(!timeItem)
			{
				timeItem = new BTableItem();
				tableWidget->setItem(i, 2, timeItem);
			}
			timeItem->setIcon(0);
			timeItem->setImage(0);
			timeItem->setText(info.timeStr);
			timeItem->setAsset(0);
			timeItem->setIconSize(0);
			timeItem->setForm(Form_IconText);
			timeItem->setAlign(Align_None);

			BTableItem* sizeItem = tableWidget->item(i, 3);
			if(!sizeItem)
			{
				sizeItem = new BTableItem();
				tableWidget->setItem(i, 3, sizeItem);
			}
			sizeItem->setIcon(0);
			sizeItem->setImage(0);
			sizeItem->setText(info.sizeStr);
			sizeItem->setAlign(Align_Right);
			sizeItem->setAsset(0);
			sizeItem->setIconSize(0);
			sizeItem->setForm(Form_IconText);
		}
		tableWidget->setColumnPolicy(Policy_Preferred | Policy_Dynamic);
		tableWidget->setRowPolicy(Policy_Preferred);
		freshTableItems();
		tableWidget->sortItems();
		tableWidget->scrollToItem(0);
		return;
	}
	int iconSize = viewComboBox->value();
	tableItems.resize(entryInfos.size());
	for (int i = 0; i < entryInfos.size(); i++)
	{
		EntryInfo& info = entryInfos[i];
		BTableItem* item = new BTableItem(info.entry->name());
		item->setForm(Form_TextUnderIcon);
		item->setAlign(Align_Center);
		item->setIconSize(iconSize);
		item->setImage(info.image);
		item->setAsset(info.entry);
		tableItems[i] = item;
	}

	int columnCount = tableWidget->centerSize().width() / (iconSize + 20);
	tableWidget->setRowSpacing(10);
	tableWidget->setColumnCount(columnCount);
	tableWidget->setColumnHeaderShown(false);
	tableWidget->setRowHeaderShown(false);
	tableWidget->setHorizontalScrollPolicy(ScrollPolicy_None);
	tableWidget->setSelectMode(Select_Multiple);
	tableWidget->clearItems();
	for (int i = 0; i < tableItems.size(); i++)
	{
		BTableItem* item = tableItems[i];
		tableWidget->insertItem(item);
	}
	tableWidget->setColumnPolicy(Policy_Fixed);
	tableWidget->setRowPolicy(Policy_Preferred);
	tableWidget->setColumnWidth(iconSize + 10);
	freshTableItems();
	tableWidget->scrollToItem(0);
}

void member_BFileDialog::openFolder(const BString& path)
{
	BString absolutePath = BFolder::FullPath(path);
	BStringList namelst = absolutePath.split('/');
#ifdef linux
	namelst.prepend("/");
#endif
	BTreeItem* item = treeWidget->itemOfText(namelst.first());
	namelst.remove(0);
	while (item && namelst.size())
	{
		if (item->childCount() == 0)
		{
			BFolder folder(item->path());
			if (folder.open())
			{
				for (int i = 0; i < folder.entryCount(); i++)
				{
					BEntry* entry = folder.entry(i);
					if (entry->attrib() & Attrib_Folder)
					{
						const BString& name = entry->name();
						BTreeItem* child = new BTreeItem(name);
						child->setAsset(entry);
						child->setIcon(iconOf(entry));
						item->addChild(child);
					}
				}
			}
		}
		treeWidget->expand(item);
		item = item->child(namelst.first());
		namelst.remove(0);
	}
	if (item)
	{
		item->setSelected(true);
		if (BListItem* symitem = symbolItem(path))
			listWidget->setItemSelected(symitem, true);
		else
			listWidget->clearSelection();
		if (pathRecords.size() == 10)
			pathRecords.remove(0);
		pathRecords.remove(pathIndex, pathRecords.size());
		pathRecords.append(absolutePath);
		pathIndex = pathRecords.size();
		freshBackFrontButton();
		BComboItem* comboItem = pathComboBox->itemOfText(absolutePath);
		if(comboItem)
			pathComboBox->moveItem(comboItem, 0);
		else
			comboItem = pathComboBox->insertItem(0, item->icon(), absolutePath);
		pathComboBox->setCurrentItem(comboItem);
	}
	entryNames.clear();
	nameEdit->setText(BString());
	okButton->setEnabled(false);
}
void member_BFileDialog::selectEntries()
{
	BString text;
	BString ext;
	for (int i = 0; i < tableWidget->selectedItemCount(); i++)
	{
		BTableItem* item = tableWidget->selectedItem(i);
		BEntry* entry = item->asset();
		if (!entry)
			continue;
		if (!(entry->attrib() & attribFilter))
			continue;
		if (attribFilter & Attrib_File && fileExts.size())
		{
			ext = item->text().ext();
			ext.lower();
			if (!fileExts.contain(ext))
				continue;
		}
		text << item->text() << ',';
	}
	text -= ",";
	nameEdit->setText(text);
	okButton->setEnabled(text.size());
}

void member_BFileDialog::slotBackButtonClicked()
{
	pathIndex--;
	const BString& path = pathRecords(pathIndex);
	pathComboBox->setCurrentText(path);
	freshBackFrontButton();
}
void member_BFileDialog::slotFrontButtonClicked()
{
	pathIndex++;
	const BString& path = pathRecords(pathIndex);
	pathComboBox->setCurrentText(path);
	freshBackFrontButton();
}
void member_BFileDialog::slotAboveButtonClicked()
{
	BString text = pathComboBox->text();
	BString abovePath = text.path();
	openFolder(abovePath);
}

void member_BFileDialog::slotPathTextChanged(BObject* object, const BValue& value)
{
	const BString& path = pathComboBox->text();
	if (path.empty())
		return;
	BFolderHolder folder = new BFolder(path, Attrib_All);
	if (folder->open())
	{
		BTreeItem* item = treeWidget->locate(path);
		treeWidget->setItemSelected(item);
		entryInfos.resize(folder->entryCount());
		for (int i = 0; i < entryInfos.size(); i++)
			entryInfos[i].clear();
		for (int i = 0; i < folder->entryCount(); i++)
		{
			BEntry* entry = folder->entry(i);
			EntryInfo& info = entryInfos[i];
			info.entry = entry;
			info.typeStr = this->typeName(entry);

			const BDate& date = entry->date();
			const BTime& time = entry->time();
			info.timeStr << date.year() << '-' << date.month() << '-' << date.day() << ' ' << time.hour() << ':' << time.minute() << ':' << time.second();

			Attrib attrib = entry->attrib();
			if (attrib & Attrib_Folder)
				continue;
			if (attrib & Attrib_Link)
				continue;
			size_t numKB = entry->size() / 1024;
			size_t modKB = entry->size() % 1024;
			if (modKB > 0)
				numKB++;
			info.sizeStr << (unsigned int)numKB << " KB";
		}
		arrangeTableItems();
	}
	freshBackFrontButton();
}
void member_BFileDialog::slotViewTextChanged(BObject* object, const BValue& value)
{
	arrangeTableItems();
}
void member_BFileDialog::slotListItemClicked(BObject* object, const BValue& value)
{
	BListItem* item = value;
	if (BDisk* disk = item->asset())
	{
		const BString& path = disk->asset();
		openFolder(path);
	}
}
void member_BFileDialog::slotTreeItemClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (!item)
		return;
	BString path = item->path();
	path.replace("//", "/");
	openFolder(path);
	if (itemEdit)
	{
		if (itemEdit->asset() != value)
		{
			itemEdit->setAsset(value);
			itemEdit->setPos(BCursor::GetPos());
		}
		else
		{
			bool editing = (itemEdit->pos() - BCursor::GetPos()).length2() > 5;
			if (item && editing)
			{
				BRect area = item->textArea();
				BSize ssize = itemEdit->shellSize();
				BRect rect = area + ssize;
				rect.right() += area.width() / 2;
				rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
				if (rect.right() >= treeWidget->centerRect().right())
					rect.right() = treeWidget->centerRect().right() - 1;
				itemEdit->setParent(treeWidget);
				itemEdit->setRect(rect);
				itemEdit->setText(item->text());
				itemEdit->popup();
			}
		}
	}
}
void member_BFileDialog::slotTreeItemDoubleClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (item)
	{
		if (item->expanded())
			treeWidget->shrink(item);
		else
			treeWidget->expand(item);
	}
}

void member_BFileDialog::slotTableWidgetFramed(BObject* object, const BValue& value)
{
	const BString& viewStr = viewComboBox->text();
	if (viewStr == "details")
		return;
	BRect crect = tableWidget->centerRect();
	BPoint offset = tableWidget->offset();
	for (int r = 0; r < tableWidget->rowCount(); r++)
	{
		BRect rect = tableWidget->rowRect(r);
		if(rect.bottom() < crect.top())
			continue;
		if(rect.top() > crect.bottom())
			continue;
		for (int c = 0; c < tableWidget->columnCount(); c++)
		{
			BTableItem* item = tableWidget->item(r, c);
			if (!item || item->image())
				continue;
			BEntry* entry = item->asset();
			int index = entryInfos.find(entry);
			EntryInfo& info = entryInfos[index];
			if (!info.ready && checkImage(info))
			{
				info.image = ReadFile<BImage>(entry->path());
				item->setImage(info.image);
				if (info.image)
					item->setIcon(0);
				info.ready = true;
				break;
			}
		}
	}
}
void member_BFileDialog::slotTableWidgetResized(BObject* object, const BValue& value)
{
	const BString& viewStr = viewComboBox->text();
	if (viewStr != "details")
	{
		int iconSize = viewComboBox->value();
		int columnCount = tableWidget->centerSize().width() / (iconSize + 20);
		if (tableWidget->columnCount() != columnCount)
		{
			tableWidget->clearItems();
			tableWidget->setColumnCount(columnCount);
			for (int i = 0; i < tableItems.size(); i++)
			{
				BTableItem* item = tableItems[i];
				tableWidget->insertItem(item);
			}
			tableWidget->setColumnPolicy(Policy_Fixed);
			tableWidget->setRowPolicy(Policy_Preferred);
			tableWidget->setColumnWidth(iconSize + 10);
			freshTableItems();
			tableWidget->scrollToItem(0);
		}
	}
}
void member_BFileDialog::slotTableItemClicked(BObject* object, const BValue& value)
{
	if (itemEdit)
	{
		BTableItem* item = value;
		if (itemEdit->asset() != value)
		{
			itemEdit->setAsset(value);
			itemEdit->setPos(BCursor::GetPos());
		}
		else
		{
			bool editing = (itemEdit->pos() - BCursor::GetPos()).length2() > 5;
			if (item && editing)
			{
				BRect area = item->textArea();
				BSize ssize = itemEdit->shellSize();
				BRect rect = area + ssize;
				rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
				if (rect.right() >= tableWidget->centerRect().right())
					rect.right() = tableWidget->centerRect().right() - 1;
				itemEdit->setParent(tableWidget);
				itemEdit->setRect(rect);
				itemEdit->setText(item->text());
				itemEdit->popup();
			}
		}
	}
}
void member_BFileDialog::slotTableItemHovered(BObject* object, const BValue& value)
{
	BString tips;
	if (BTableItem* item = value)
	{
		BEntry* entry = item->asset();
		for (int i = 0; i < entryInfos.size(); i++)
		{
			EntryInfo& info = entryInfos[i];
			if (info.entry == entry)
			{
				tips << info.entry->name() << '\n';
				if (info.t_typeStr.size())
					tips << "type : " << info.t_typeStr << '\n';
				else
					tips << "type : " << info.typeStr << '\n';
				if (0 == (entry->attrib() & Attrib_Folder))
				{
					tips << "size : " << (BULong)entry->size() << " B\n";
				}
				tips << "time : " << info.timeStr;
				break;
			}
		}
	}
	tableWidget->setTips(tips);
}
void member_BFileDialog::slotTableItemDoubleClicked(BObject* object, const BValue& value)
{
	BTableItem* item = value;
	if (item)
	{
		BEntry* entry = (BEntry*)item->asset();
		if (entry->attrib() & Attrib_Folder)
		{
			openFolder(entry->path());
		}
		else if (entry->attrib() & Attrib_Link)
		{
			BValue value;
			if (entry->query("target", value))
			{
				const BString& path = value;
				openFolder(path);
			}
		}
		else
		{
			selectEntries();
			if (okButton->enabled())
			{
				boss->close(1);
			}
		}
	}
}
void member_BFileDialog::slotTableWidgetSelectionChanged(BObject* object, const BValue& value)
{
	selectEntries();
}

void member_BFileDialog::slotScrollAreaChanged(BObject* object, const BValue& value)
{
	if (itemEdit && itemEdit->visible())
	{
		BSize ssize = itemEdit->shellSize();
		if (BTreeItem* item = itemEdit->asset())
		{
			BRect area = item->textArea();
			BRect rect = area + ssize;
			rect.right() += area.width() / 2;
			rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
			if (rect.right() >= treeWidget->centerRect().right())
				rect.right() = treeWidget->centerRect().right() - 1;
			itemEdit->setRect(rect);
			return;
		}
		if (BTableItem* item = itemEdit->asset())
		{
			BRect area = item->textArea();
			BRect rect = area + ssize;
			rect.right() += area.width() / 2;
			rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
			if (rect.right() >= tableWidget->centerRect().right())
				rect.right() = tableWidget->centerRect().right() - 1;
			itemEdit->setRect(rect);
			return;
		}
	}
}
void member_BFileDialog::slotItemEditFocused(BObject* object, const BValue& value)
{
	if (value == false)
	{
		itemEdit->setAsset(BValue());
		itemEdit->hide();
	}
}
void member_BFileDialog::slotItemEditFinished(BObject* object, const BValue& value)
{
	if (BTreeItem* item = object->asset())
	{
		if (item->text() != itemEdit->text())
		{
			BEntry* entry = item->asset();
			if (entry->attrib() & Attrib_File)
			{
				if (BFile::Rename(entry->path(), itemEdit->text()))
					item->setText(itemEdit->text());
			}
			if (entry->attrib() & Attrib_Folder)
			{
				if (BFolder::Rename(entry->path(), itemEdit->text()))
					item->setText(itemEdit->text());
			}
		}
		return;
	}
	if (BTableItem* item = object->asset())
	{
		if (item->text() != itemEdit->text())
		{
			BEntry* entry = item->asset();
			if (entry->attrib() & Attrib_File)
			{
				if (BFile::Rename(entry->path(), itemEdit->text()))
					item->setText(itemEdit->text());
			}
			if (entry->attrib() & Attrib_Folder)
			{
				if (BFolder::Rename(entry->path(), itemEdit->text()))
					item->setText(itemEdit->text());
			}
		}
		return;
	}
}
void member_BFileDialog::slotNameEdited(BObject* object, const BValue& value)
{
	const BString& text = nameEdit->text();
	okButton->setEnabled(text.size() > 0);
}
void member_BFileDialog::slotNameFilterChanged(BObject* object, const BValue& value)
{
	fileExts.clear();
	const BString& text = filterComboBox->text();
	int pos = 0;
	while (pos < text.size())
	{
		pos = text.find('.', pos);
		BString ext;
		pos = text.word(ext, pos + 1);
		if (CheckWord(ext))
		{
			ext.lower();
			fileExts.append(ext);
		}
	}
	selectEntries();
}

void member_BFileDialog::slotOkClicked()
{
	boss->close(1);
}
void member_BFileDialog::slotCancleClicked()
{
	boss->close(0);
}
